﻿using System.IO;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Text;
using System.Windows.Forms;
using Plasmoid.Extensions;
using System;
using DevToolkit.CustomClasses;

namespace DevToolkit
{
    public partial class Validation : Form
    {
        #region Other Sections
        // For the item list to show check mark or the x mark for problems
        public class Item
        {
            public string name;
            public Image image;

            public Item(string naming, Image imageName)
            {
                name = naming;
                image = imageName;
            }

            public override string ToString()
            {
                return name;
            }
        }

        struct Error
        {
            public string Section;
            public string error;

            public Error(string section, string errorDesc)
            {
                Section = section;
                error = errorDesc;
            }
        }

        private const int ItemMargin = 5;
        private const float PictureHeight = 25f;
        RequiredInfo info;
        string packageLocation;
        List<Error> errors;
        IniFile file;
        bool validation = false;

        int files, dirs, app, launch = 0;

        public RequiredInfo Info
        {
            get { return info; }
            set { info = value; }
        }

        public bool ValidationPassed
        {
            get { return validation; }
        }

        #endregion

        public Validation(string package, string removeDrive)
        {
            InitializeComponent();
            Listbox.DrawMode = DrawMode.OwnerDrawVariable;
            packageLocation = package;
            errors = new List<Error>();

            RefreshButton_Click(null, null);

            //Listbox.Items.Add(new Item("Overview", Properties.Resources.NotDone));
            //Listbox.Items.Add(new Item("Directories", Properties.Resources.NotDone));
            //Listbox.Items.Add(new Item("AppInfo.ini", Properties.Resources.NotDone));
            //Listbox.Items.Add(new Item("Launcher.ini", Properties.Resources.NotDone));
        }

        // Return enough space for the item.
        private void Listbox_MeasureItem(object sender, MeasureItemEventArgs e)
        {
            e.ItemHeight = (int)(PictureHeight + 2 * ItemMargin);
        }

        // Draw the item.
        private void Listbox_DrawItem(object sender, DrawItemEventArgs e)
        {
            // Get the ListBox and the item.
            ListBox lst = sender as ListBox;
            Item item = lst.Items[e.Index] as Item;

            // Draw the background.
            e.DrawBackground();

            // Draw the picture.
            float scale = PictureHeight / item.image.Height;
            RectangleF source_rect = new RectangleF(
                0, 0, item.image.Width, item.image.Height);

            float picture_width = scale * item.image.Width;
            RectangleF dest_rect = new RectangleF(
                e.Bounds.Left + ItemMargin, e.Bounds.Top + ItemMargin,
                picture_width, PictureHeight);

            e.Graphics.DrawImage(item.image, dest_rect, source_rect, GraphicsUnit.Pixel);

            // See if the item is selected.
            System.Drawing.Brush br;
            if ((e.State & DrawItemState.Selected) == DrawItemState.Selected)
                br = SystemBrushes.HighlightText;
            else
                br = new SolidBrush(e.ForeColor);

            // Find the area in which to put the text.
            float x = e.Bounds.Left + picture_width + 3 * ItemMargin;
            float y = e.Bounds.Top + ItemMargin;
            float width = e.Bounds.Right - ItemMargin - x;
            float height = e.Bounds.Bottom - ItemMargin - y;
            RectangleF layout_rect = new RectangleF(x, y, width, height);

            // Outline the text.
            //e.Graphics.DrawRectangle(Pens.Red, Rectangle.Round(layout_rect));

            System.Drawing.Drawing2D.LinearGradientBrush brush = new System.Drawing.Drawing2D.LinearGradientBrush(layout_rect, Color.WhiteSmoke, Color.LightSkyBlue, LinearGradientMode.Vertical);
            e.Graphics.FillRoundedRectangle(brush, layout_rect, 8, RectangleEdgeFilter.TopLeft | RectangleEdgeFilter.BottomRight);

            // Draw the text.
            string txt = item.name;
            Font font = new Font(this.Font, FontStyle.Bold);
            e.Graphics.DrawString(txt, font, br, (float)layout_rect.X + 15, (float)layout_rect.Y + 5);

            // Draw the focus rectangle if appropriate.
            e.DrawFocusRectangle();
        }

        private void Listbox_SelectedValueChanged(object sender, EventArgs e)
        {
            // Changes the textbox based upon the stuff
            if (errors.Count > 0)
            {
                ErrorTextbox.Clear();
                foreach (Error temp in errors)
                {
                    if (Listbox != null)
                    {
                        if ("Overview" == Listbox.SelectedItem.ToString())
                            ErrorTextbox.AppendText(temp.error + Environment.NewLine);
                        else if (temp.Section == Listbox.SelectedItem.ToString())
                            ErrorTextbox.AppendText(temp.error + Environment.NewLine);
                    }
                }
            }
        }

        private void RefreshButton_Click(object sender, EventArgs e)
        {
            // clear the errors list so not to get duplicates
            errors.Clear();

            //==============================================================
            // checking initial directories
            //==============================================================
            if (Directory.Exists(packageLocation + "/App") == false)
                errors.Add(new Error("Directories", "ERROR: " + "<BaseDir>/App directory is missing"));
            else if (Directory.Exists(packageLocation + "/App/AppInfo") == false)
                errors.Add(new Error("Directories", "ERROR: " + "<BaseDir>/App/AppInfo directory is missing"));
            
            //==============================================================
            // Checking for required files
            //==============================================================
            if (File.Exists(packageLocation + "/help.html") == false)
                errors.Add(new Error("Files", "ERROR: " + "help.html file is missing"));

            //==============================================================
            // Checking the appinfo information
            //==============================================================
            if (File.Exists(packageLocation + "/App/AppInfo/appinfo.ini") == false)
            {
                errors.Add(new Error("Files", "ERROR: " + "appinfo.ini file is missing"));
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "appinfo.ini file is missing"));
            }
            else
            {
                // Validate each section of the ini file
                ValidateFormatSection();
                ValidateDetailSection();
                ValidateLicenseSection();

                ValidateVersionSection();
                ValidateControlSection();
                ValidateSpecialPathsSection();

                //==============================================================
                // Checking the launcher file
                //==============================================================
                string name = string.Empty;
                if (file.ReadValue("Name", "Details").Contains("Portable") == false)
                    name = file.ReadValue("Name", "Details") + "Portable";
                else
                    name = file.ReadValue("Name", "Details");

                if (File.Exists(packageLocation + "/App/AppInfo/Launcher/" + name + ".ini") == false)
                {
                    errors.Add(new Error("Files", "ERROR: " + "launcher.ini file is missing"));
                    errors.Add(new Error("Launcher.ini", "ERROR: " + "launcher.ini file is missing"));
                }
                else
                {
                    string launch = file.ReadValue("ProgramExecutable", "Launch");
                    if (launch != string.Empty)
                    {
                        string[] launches = launch.Split('/');
                        if (Directory.Exists(packageLocation + "/App/" + launches[0]) == false)
                        {
                            errors.Add(new Error("Directories", "ERROR: " + "<BaseDir>/App/<AppDir> directory does not exist"));
                            errors.Add(new Error("Launcher.ini", "ERROR: " + "<BaseDir>/App/<AppDir> directory does not exist"));
                        }
                        else
                        {
                            if (File.Exists(packageLocation + "/App/" + launches[0] + "/" + launches[1]) == false)
                            {
                                errors.Add(new Error("Files", "ERROR: " + "Launcher.ini file is missing"));
                                errors.Add(new Error("Launcher.ini", "ERROR: " + "Launcher.ini file is missing"));
                            }
                            else
                            {
                                IniFile tempLaunch = new IniFile(packageLocation + "/App/AppInfo/" + name + ".ini");
                                if (tempLaunch.ReadValue("ExecuteableProgram", "Launch").Length < 0)
                                    errors.Add(new Error("Launcher.ini", "ERROR: " + "Launch - ExecutableProgram key is missing"));
                            }
                        }
                    }
                }
            }

            // Add sections to the listbox
            if (errors.Count > 0)
            {
                Listbox.Items.Clear();
                ErrorsList();
                Listbox.Items.Add(new Item("Overview", Properties.Resources.NotDone));
                
                if (dirs > 0)
                    Listbox.Items.Add(new Item("Directories", Properties.Resources.NotDone));
                else
                    Listbox.Items.Add(new Item("Directories", Properties.Resources.Done));

                if (files > 0)
                    Listbox.Items.Add(new Item("Files", Properties.Resources.NotDone));
                else
                    Listbox.Items.Add(new Item("Files", Properties.Resources.Done));

                if (app > 0)
                    Listbox.Items.Add(new Item("AppInfo.ini", Properties.Resources.NotDone));
                else
                    Listbox.Items.Add(new Item("AppInfo.ini", Properties.Resources.Done));

                if (launch > 0)
                    Listbox.Items.Add(new Item("Launcher.ini", Properties.Resources.NotDone));
                else
                    Listbox.Items.Add(new Item("Launcher.ini", Properties.Resources.Done));

                Listbox.SelectedIndex = 0;
                foreach (Error temp in errors)
                {
                    ErrorTextbox.Clear();
                    ErrorTextbox.AppendText(temp.error + Environment.NewLine);
                }
            }
            else
            {
                Listbox.Items.Clear();
                Listbox.Items.Add(new Item("Overview", Properties.Resources.Done));
                Listbox.Items.Add(new Item("Directories", Properties.Resources.Done));
                Listbox.Items.Add(new Item("Files", Properties.Resources.Done));
                Listbox.Items.Add(new Item("AppInfo.ini", Properties.Resources.Done));
                Listbox.Items.Add(new Item("Launcher.ini", Properties.Resources.Done));

                validation = true;
            }
        }

        #region Validation Section

        private void DisplayAllErrors()
        {
            ErrorTextbox.Clear();
            foreach (Error err in errors)
                ErrorTextbox.AppendText(err.error);
        }
        private void ErrorsList()
        {
            foreach(Error temp in errors)
            {
                if (temp.Section == "Directories")
                    dirs++;
                else if (temp.Section == "Files")
                    files++;
                else if (temp.Section == "AppInfo.ini")
                    app++;
                else if (temp.Section == "Launcher.ini")
                    launch++;
            }
        }

        private void ValidateFormatSection()
        {
            // Load the file
            file = new IniFile(packageLocation + "/App/AppInfo/appinfo.ini");
            
            // Checking for key exists
            if (file.ReadValue("Type", "Format").Length > 0)
            {
                // Validating the value
                if (file.ReadValue("Type", "Format") != "PortableApps.comFormat")
                    errors.Add(new Error("AppInfo.ini", "ERROR: " + "Type is not valid"));
            }
            else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "Format - Type key is missing"));

            if(file.ReadValue("Version", "Format").Length > 0)
            {
                if (file.ReadValue("Version", "Format") != "3.0")
                    errors.Add(new Error("AppInfo.ini", "ERROR: " + "Version is not valid"));
            }
            else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "Format - Version key is missing"));
        }
        private void ValidateDetailSection()
        {
            // Load the file
            file = new IniFile(packageLocation + "/App/AppInfo/appinfo.ini");
            
            //================================================================
            // Checking for name
            if (file.ReadValue("Name", "Details").Length <= 0)
            //    errors.Add(new Error("AppInfo.ini", "ERROR: " + "Name is not valid"));
            //else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "Details - Name key is missing"));
            
            //================================================================
            // Checking for ID
            if (file.ReadValue("AppID", "Details").Length <= 0)
            //    errors.Add(new Error("AppInfo.ini", "ERROR: " + "AppID is not valid"));
            //else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "Details - AppID key is missing"));

            //================================================================
            // Checking for name
            if (file.ReadValue("Publisher", "Details").Length <= 0)
                //    errors.Add(new Error("AppInfo.ini", "ERROR: " + "Publisher is not valid"));
                //else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "Details - Publisher key is missing"));

            //================================================================
            // Checking for name
            if (file.ReadValue("Homepage", "Details").Length <= 0)
                //    errors.Add(new Error("AppInfo.ini", "ERROR: " + "Homepage is not valid"));
                //else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "Details - Homepage key is missing"));

            //================================================================
            // Checking for name
            if (file.ReadValue("Category", "Details").Length <= 0)
                //    errors.Add(new Error("AppInfo.ini", "ERROR: " + "Category is not valid"));
                //else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "Details - Category key is missing"));

            //================================================================
            // Checking for name
            if (file.ReadValue("Homepage", "Details").Length <= 0)
                //    errors.Add(new Error("AppInfo.ini", "ERROR: " + "Homepage is not valid"));
                //else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "Details - Homepage key is missing"));

            //================================================================
            // Checking for name
            if (file.ReadValue("Description", "Details").Length <= 0 && file.ReadValue("Description", "Details").Length > 512)
                //    errors.Add(new Error("AppInfo.ini", "ERROR: " + "Description is not valid"));
                //else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "Details - Description key is missing"));

            //================================================================
            // Checking for name
            if (file.ReadValue("Language", "Details").Length <= 0)
                //    errors.Add(new Error("AppInfo.ini", "ERROR: " + "Language is not valid"));
                //else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "Details - Language key is missing"));

            //================================================================
            // Checking for name
            //if (file.ReadValue("Trademarks", "Details").Length <= 0)
            //    errors.Add(new Error("AppInfo.ini", "ERROR: " + "Trademarks is not valid"));
            //else
            //    errors.Add(new Error("AppInfo.ini", "ERROR: " + "Details - Trademarks key is missing"));
        }
        private void ValidateLicenseSection()
        {
            // Load the file
            file = new IniFile(packageLocation + "/App/AppInfo/appinfo.ini");

            // Checking for key exists
            if (file.ReadValue("Shareable", "License").Length > 0)
            {
                if (file.ReadValue("Shareable", "License").ToLower() != "False".ToLower() && file.ReadValue("Shareable", "License").ToLower() != "True".ToLower())
                    errors.Add(new Error("AppInfo.ini", "ERROR: " + "Shareable is not valid"));
            }
            else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "License - Shareable key is missing"));

            if (file.ReadValue("OpenSource", "License").Length > 0)
            {
                if (file.ReadValue("OpenSource", "License").ToLower() != "False".ToLower() && file.ReadValue("OpenSource", "License").ToLower() != "True".ToLower())
                    errors.Add(new Error("AppInfo.ini", "ERROR: " + "OpenSource is not valid"));
            }
            else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "License - OpenSource key is missing"));

            if (file.ReadValue("Freeware", "License").Length > 0)
            {
                if (file.ReadValue("Freeware", "License").ToLower() != "False".ToLower() && file.ReadValue("Freeware", "License").ToLower() != "True".ToLower())
                    errors.Add(new Error("AppInfo.ini", "ERROR: " + "Freeware is not valid"));
            }
            else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "License - Freeware key is missing"));

            if (file.ReadValue("CommercialUse", "License").Length > 0)
            {
                if (file.ReadValue("CommercialUse", "License").ToLower() != "False".ToLower() && file.ReadValue("CommercialUse", "License").ToLower() != "True".ToLower())
                    errors.Add(new Error("AppInfo.ini", "ERROR: " + "CommercialUse is not valid"));
            }
            else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "License - CommercialUse key is missing"));
        }

        private void ValidateVersionSection()
        {
            // Load the file
            file = new IniFile(packageLocation + "/App/AppInfo/appinfo.ini");

            // Checking for key exists
            if (file.ReadValue("PackageVersion", "Version").Length > 0)
            {
                string[] temp = file.ReadValue("PackageVersion", "Version").Split('.');
                if( temp.Length != 4 )
                    errors.Add(new Error("AppInfo.ini", "ERROR: " + "PackageVersion is not valid"));
            }
            else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "Version - PackageVersion key is missing"));


            if (file.ReadValue("DisplayVersion", "Version").Length < 1)
            //    errors.Add(new Error("AppInfo.ini", "ERROR: " + "DisplayVersion is not valid"));
            //else
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "Version - DisplayVersion key is missing"));
        }
        private void ValidateControlSection()
        {
            // Load the file
            file = new IniFile(packageLocation + "/App/AppInfo/appinfo.ini");

            // Checking for key exists
            if (file.ReadValue("Icons", "Control").Length <= 0)
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "Control - Icons key is missing "));

            if (file.ReadValue("Start", "Control").Length < 1)
            {
                errors.Add(new Error("AppInfo.ini", "ERROR: " + "Control - Start key is missing"));
                //string start = file.ReadValue("Start", "Control");
                //if (File.Exists(packageLocation + "/App/" + start + ".exe") == false)
                //    errors.Add(new Error("AppInfo.ini", "ERROR: " + "Control - Start file does not exist"));
            }
        }
        private void ValidateSpecialPathsSection()
        {
            // Load the file
            file = new IniFile(packageLocation + "/App/AppInfo/appinfo.ini");

            // Checking for key exists
            if (file.ReadValue("Plugins", "SpecialPaths").Length > 0)
            {
                if (Directory.Exists(packageLocation + file.ReadValue("Plugins", "SpecialPaths")) == false)
                    errors.Add(new Error("AppInfo.ini", "ERROR: " + "SpecialPaths - Plugins path does not exist"));
            }
        }

        #endregion
    }
}
